/*
 * Copyright (c) 2001-2016, Alliance for Open Media. All rights reserved
 *
 * This source code is subject to the terms of the BSD 2 Clause License and
 * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
 * was not distributed with this source code in the LICENSE file, you can
 * obtain it at www.aomedia.org/license/software. If the Alliance for Open
 * Media Patent License 1.0 was not distributed with this source code in the
 * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
 */

/* clang-format off */

#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

#include <stdio.h>

#include "aom_dsp/bitreader.h"
#include "av1/common/generic_code.h"
#include "av1/common/odintrin.h"
#include "pvq_decoder.h"

/** Decodes a value from 0 to N-1 (with N up to 16) based on a cdf and adapts
 * the cdf accordingly.
 *
 * @param [in,out] r     multi-symbol entropy decoder
 * @param [in,out] cdf   CDF of the variable (Q15)
 * @param [in]     n     number of values possible
 * @param [in,out] count number of symbols encoded with that cdf so far
 * @param [in]     rate  adaptation rate shift (smaller is faster)
 * @return decoded variable
 */
int aom_decode_cdf_adapt_q15_(aom_reader *r, uint16_t *cdf, int n,
 int *count, int rate ACCT_STR_PARAM) {
  int val;
  int i;
  if (*count == 0) {
    int ft;
    ft = cdf[n - 1];
    for (i = 0; i < n; i++) {
      cdf[i] = AOM_ICDF(cdf[i]*32768/ft);
    }
  }
  val = aom_read_cdf(r, cdf, n, ACCT_STR_NAME);
  aom_cdf_adapt_q15(val, cdf, n, count, rate);
  return val;
}

/** Encodes a random variable using a "generic" model, assuming that the
 * distribution is one-sided (zero and up), has a single mode, and decays
 * exponentially past the model.
 *
 * @param [in,out] r     multi-symbol entropy decoder
 * @param [in,out] model generic probability model
 * @param [in]     x     variable being encoded
 * @param [in,out] ExQ16 expectation of x (adapted)
 * @param [in]     integration integration period of ExQ16 (leaky average over
 * 1<<integration samples)
 *
 * @retval decoded variable x
 */
int generic_decode_(aom_reader *r, generic_encoder *model,
 int *ex_q16, int integration ACCT_STR_PARAM) {
  int lg_q1;
  int shift;
  int id;
  uint16_t *cdf;
  int xs;
  int lsb;
  int x;
  lsb = 0;
  lg_q1 = log_ex(*ex_q16);
  /* If expectation is too large, shift x to ensure that
     all we have past xs=15 is the exponentially decaying tail
     of the distribution. */
  shift = OD_MAXI(0, (lg_q1 - 5) >> 1);
  /* Choose the cdf to use: we have two per "octave" of ExQ16. */
  id = OD_MINI(GENERIC_TABLES - 1, lg_q1);
  cdf = model->cdf[id];
  xs = aom_read_symbol_pvq(r, cdf, 16, ACCT_STR_NAME);
  if (xs == 15) {
    int e;
    unsigned decay;
    /* Estimate decay based on the assumption that the distribution is close
       to Laplacian for large values. We should probably have an adaptive
       estimate instead. Note: The 2* is a kludge that's not fully understood
       yet. */
    OD_ASSERT(*ex_q16 < INT_MAX >> 1);
    e = ((2**ex_q16 >> 8) + (1 << shift >> 1)) >> shift;
    decay = OD_MAXI(2, OD_MINI(254, 256*e/(e + 256)));
    xs += aom_laplace_decode_special(r, decay, ACCT_STR_NAME);
  }
  if (shift != 0) {
    int special;
    /* Because of the rounding, there's only half the number of possibilities
       for xs=0 */
    special = xs == 0;
    if (shift - special > 0) {
      lsb = aom_read_literal(r, shift - special, ACCT_STR_NAME);
    }
    lsb -= !special << (shift - 1);
  }
  x = (xs << shift) + lsb;
  generic_model_update(ex_q16, x, integration);
  OD_LOG((OD_LOG_ENTROPY_CODER, OD_LOG_DEBUG,
   "dec: %d %d %d %d %d %x", *ex_q16, x, shift, id, xs, dec->rng));
  return x;
}
